package de.dnb.gnd.utils.formatter;

import java.util.Collection;
import java.util.Iterator;

import de.dnb.basics.Constants;
import de.dnb.basics.applicationComponents.RangeCheckUtils;
import de.dnb.gnd.parser.Format;
import de.dnb.gnd.parser.Indicator;
import de.dnb.gnd.parser.Record;
import de.dnb.gnd.parser.Subfield;
import de.dnb.gnd.parser.line.Line;
import de.dnb.gnd.parser.tag.Tag;
import de.dnb.gnd.parser.tag.TagDB;
import de.dnb.gnd.utils.RecordUtils;

public abstract class AbstractFormatter {

	protected Format format = Format.PICA3;

	protected String recordPre = "";
	protected String recordPost = "";

	protected String linePre = "";
	protected String linePost = "";
	protected String lineSep = Constants.LINE_SEPARATOR;

	protected String tagPre = "";
	protected String tagPost = " ";

	protected String subfieldsPre = "";
	protected String subfieldsPost = "";

	protected String subfieldSeparator = "";
	protected String subfieldPre = "";
	protected String subfieldPost = "";

	protected String indicatorSign = Character.toString(Constants.DOLLAR);
	protected String indicatorPre = "";
	protected String indicatorPost = "";

	protected Tag actualTag;

	/**
	 * Aktuelles Unterfeld ist das erste der Liste.
	 */
	protected boolean isFirstSubfield;

	protected boolean isFirstAttaching;

	protected Indicator actualIndicator;

	protected Record actualRecord;

	protected TagDB tagDB;

	public void setRecord(Record record) {
		RangeCheckUtils.assertReferenceParamNotNull("record", record);
		actualRecord = record;
		tagDB = record.tagDB;
	}

	public String format(Record record) {
		setRecord(record);
		String s = recordPre;
		Iterator<Line> iterator = getIterator(record);
		for (; iterator.hasNext();) {
			Line line = (Line) iterator.next();
			s += format(line);
			if (iterator.hasNext())
				s += lineSep;
		}
		s += recordPost;
		return s;
	}

	public Iterator<Line> getIterator(Record record) {
		return record.iterator();
	}

	public String format(Line line) {
		actualTag = line.getTag();
		String s = linePre;
		s += formatTag();
		Collection<Subfield> subfields = line.getSubfields(format);
		s += format(subfields);
		s += linePost;
		return s;
	}

	public String formatTag() {
		String s = tagPre;
		s += getTagString(actualTag);
		s += tagPost;
		return s;
	}

	public String getTagString(Tag tag) {
		return tag.pica3;
	}

	public String format(Collection<Subfield> subfields) {
		isFirstSubfield = true;
		isFirstAttaching = true;

		String s = subfieldsPre;
		for (Iterator<Subfield> iterator = subfields.iterator(); iterator
			.hasNext();) {
			Subfield subfield = iterator.next();
			actualIndicator = subfield.getIndicator();
			s += format(subfield);
			isFirstSubfield = false;
			if (iterator.hasNext())
				s += subfieldSeparator;
		}
		s += subfieldsPost;
		return s;
	}

	/**
	 * Standardverhalten. Muss sonst überschrieben werden.
	 * 
	 * @param subfield	nicht null
	 * @return	formatiertes Unterfeld
	 */
	protected String format(final Subfield subfield) {
		String s = subfieldPre;
		s += formatIndicator() + formatContent(subfield.getContent());
		s += subfieldPost;
		return s;
	}

	/**
	 * Muss überschrieben werden, wenn Content (z.B. für HTML) noch 
	 * überarbeitet werden muss.
	 * 
	 * @param content	Inhalt des Unterfeldes
	 * @return			content im Normalfall
	 */
	protected String formatContent(String content) {
		return content;
	}

	protected String formatIndicator() {
		return indicatorPre + indicatorSign + getIndicatorChar()
			+ indicatorPost;
	}

	protected String getIndicatorChar() {
		return Character.toString(actualIndicator.indicatorChar);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Record record = RecordUtils.readFromClip();
		AbstractFormatter formatter = new AbstractFormatter() {
		};
		System.out.println(formatter.format(record));

	}

}
